/**
 *
 */
package com.naiterui.ehp.bp.utils.sms;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.naiterui.common.redis.RedisUtil;
import com.naiterui.ehp.bp.constants.CommonConstant;
import com.naiterui.ehp.bp.support.exception.BaseExceptionCodes;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bp.utils.lang.ConfigUtil;
import com.naiterui.ehp.bp.utils.notice.SendMessageUtil;

/**
 * @Description 概述
 */
public class SMSUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(SMSUtil.class);
    private static String url = ConfigUtil.getString("api.sms.singlesned.url");
    private static SendMessageUtil sendMessageUtil = new SendMessageUtil(url);

    public enum Template {
        /**
         * 注册
         */
        REG(ConfigUtil.getString("message_reg_tmplate")),
        /**
         * 密码找回
         */
        PWD(ConfigUtil.getString("message_pwd_tmplate")),
        /**
         * 3天未登陆提醒
         */
        DR_NOT_LOGIN(ConfigUtil.getString("send.unlogin.msg")),
        /**
         * 购药咨询提醒文案
         */
        REQUIER_REMIND_FIRST_TEMPLATE(ConfigUtil.getString("doctor.require.remind.msg.first.templateid")),
        /**
         * 购药咨询第二次提醒文案
         */
        REQUIER_REMIND_SECOND_TEMPLATE(ConfigUtil.getString("doctor.require.remind.msg.second.templateid")),
        /**
         * 医生积分增加
         */
        DR_POINT_ADD(ConfigUtil.getString("message_dr_pointAdd_tmplate")),
        /**
         * 步长医生积分增加-非步长医生短信文案
         */
        IS_NOT_BC_DR_POINT_ADD(ConfigUtil.getString("message_is_not_bc_dr_pointAdd_tmplate")),
        /**
         * 疗效反馈-推荐购药
         */
        DR_MEDIC_VISIT_RECOM_POINT_ADD(ConfigUtil.getString("message_dr_medic_visit_recom_pointAdd_tmplate")),
        /**
         * 疗效反馈-主动购药
         */
        DR_MEDIC_VISIT_ACTIVE_POINT_ADD(ConfigUtil.getString("message_dr_medic_visit_active_pointAdd_tmplate")),
        /**
         * 首次登陆医生，72小时未提交认证提醒
         */
        DR_OVER_DUE_AUDIT(ConfigUtil.getString("message.dr.audit.remind.template")),
        /**
         * 医生拒绝发送短信模板
         */
        DR_REJECT_VIDEO(ConfigUtil.getString("reservation.sms.template")),
        /**
         * 系统取消订单模板
         */
        SYSTEM_CANCEL_SMS(ConfigUtil.getString("reservation.system.cancel.sms.template")),
        /*医生超时未发起的预约订单详情*/
        SYSTEM_CANCEL_SMS_PATIENT_TIMEOUT(ConfigUtil.getString("reservation.system.cancel.patient.timeout.templateid")),
        /*患者超时未接通的预约订单详情*/
        SYSTEM_CANCEL_SMS_PATIENT_NOANSWER(ConfigUtil.getString("reservation.system.cancel.patient.noanswer.templateid")),
        /*医生订单完成发送短信*/
        DR_POINT_VIDEO(ConfigUtil.getString("reservation.video.service.point.template")),
        /**
         * 预约时间到点提醒医生
         */
        DR_REMIND(ConfigUtil.getString("reservation.sms.remind.templateid")),
        /**
         * 医生备案通过
         **/
        RECORD_SUCCESS(ConfigUtil.getString("record.success.sms.template")),
        /**
         * 医生备案失败
         **/
        RECORD_FAIL(ConfigUtil.getString("record.fail.sms.template")),
        /**
         * 要求医生备案
         **/
        RECORD_REQUIRED(ConfigUtil.getString("record.required.sms.template")),
        /**
         * 30天未购发送微信失败发送短信
         */
        PATIENT_RE_PURCHASE_TEMPLATE(ConfigUtil.getString("patient_re_purchase")),

        RECORD_NO(ConfigUtil.getString("record.no.sms.template")),

        /**
         * 非阳光化医生，0积分短信文案
         */
        DR_NO_POINT_ADD_TEMPLATE(ConfigUtil.getString("doctor.no.point.add.template")),

        /**
         * 阳光化病例数据收集短信文案
         */
        DR_PUBLIC_POINT_ADD_COLLECT_TEMPLATE(ConfigUtil.getString("doctor.public.point.collect.template")),

        /**
         * 用户流失问卷调查，短信文案
         */
        QUESTIONNAIRE_USER_TEMPLATE(ConfigUtil.getString("questionnaire.user.template")),

        /**
         * 医生审核通过短信文案
         */
        AUDIT_PASS_TEMPLATE(ConfigUtil.getString("audit.success.msg.template")),

        /**
         * H5页注册后通知医生注册成功
         */
        DOCTOR_REGIS_H5_SUCCESS_TEMPLATE(ConfigUtil.getString("doctor.regist.h5.sms.template")),
        /**
         * 未审核处方汇总短信通知文案
         */
        RECOM_PENDING_SUMMARY("10046"),
        /**
         * 无未审核处方短信通知文案
         */
        RECOM_PENDING_NO("10047"),

        /**
         * 用药提醒
         */
        MEDICATION_REMINDER_NOTICE_TEMPLATE("10048");

        private String templateId;

        Template(String templateId) {
            this.templateId = templateId;
        }

        public String getTemplateId() {
            return this.templateId;
        }

        public void setTemplateId(String templateId) {
            this.templateId = templateId;
        }
    }

    /**
     * <根据模板发送短信>
     * @param phone
     * @param tmpl
     * @param args void <返回值描述>
     * @Throws 异常信息
     * @History 2015-8-21 下午2:30:02 by guoyongxiang
     */
    public static void sendSMS(String phone, Template tmpl, Object... args) {
        String templateId = tmpl.getTemplateId();
        LOGGER.info("[smsSend]短信发送phone: {}, templateId: {}, params: {}", phone, templateId, args);
        try {
            sendMessageUtil.sendSms(phone, templateId, args);
        } catch (Exception e) {
            LOGGER.warn("[smsSend]短信模板内容为空phone: {}, templateId: {}, params: {}", phone, templateId, args, e);
        }
    }

    /**
     * 验证手机号获取验证码是否正确
     * LoginController.validCode()
     *
     * @param verifyCode
     * @param redisKey
     * @param businessKey  业务服务key,如：CommonConstant.REDIS_PRE_DR
     *
     * @throws BusinessException
     * @Author chenlin
     * @Date 2016年3月25日
     * @since 1.0.0
     */
    public static void validCode(String verifyCode, String redisKey, String businessKey) throws BusinessException {
        if (verifyCode == null || "".equals(verifyCode)) {
            throw new BusinessException(BaseExceptionCodes.SMS_PHONE_VALID_NULL);
        }
        String cacheVerifyCode = RedisUtil.valueOps().getString(redisKey);
        if (StringUtils.isEmpty(cacheVerifyCode)) {
            throw new BusinessException(BaseExceptionCodes.SMS_PHONE_VALID_ERROR);
        }
        try {
            if (!verifyCode.trim().equalsIgnoreCase(cacheVerifyCode)) {
                // 连续输入错误次数控制
                if (validUserOperator(businessKey, redisKey)) {
                    RedisUtil.keyOps().delete(redisKey);
                    throw new BusinessException(BaseExceptionCodes.SMS_PHONE_VALID_ERROR);
                }
                throw new BusinessException(BaseExceptionCodes.SMS_PHONE_VALID_ERROR);
            }
            RedisUtil.keyOps().delete(redisKey);
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error("从redis获取医生验证码失败,redisKey=" + redisKey);
            throw new BusinessException(BaseExceptionCodes.FAILED);
        }
    }

    /**
     *   算验证错误次数并判断redisKey对应的错误验证码验证次数是否在规定时间内超过规定值，
     *   如果超过验证次数，则返回true,否则返回false.
     * @param businessKey  业务服务key,如：CommonConstant.REDIS_PRE_DR
     * @param cacheKey
     * @return
     */
    public static boolean validUserOperator(String businessKey, String cacheKey) {
        // 根据业务cacheKey，计算出验证validCacheKey和validCacheKey
        String validCacheCountKey = cacheKey + "|key";
        String validCacheTimeKey = cacheKey + "|time";
        String validKey = businessKey + "valid_exp";
        // 缓存中获取验证次数记录周期
        Object avlTimeObj = RedisUtil.hashOps().hget(validKey, CommonConstant.VALID_TIME_FIELD);
        Integer avlTime = Integer.parseInt(avlTimeObj == null ? "0" : String.valueOf(avlTimeObj));
        if (avlTime == 0) {
            avlTime = CommonConstant.DEFAULT_TIME_FIELD;
        }
        // validCacheTimeKey用于记录验证用户操作的周期
        // validCacheKey用于记录验证用户操作的次数
        if (!RedisUtil.keyOps().existsKey(validCacheTimeKey)) {
            RedisUtil.valueOps().set(validCacheTimeKey, "", avlTime);
            RedisUtil.keyOps().delete(validCacheCountKey);
        }
        // 缓存中获取验证次数
        long validCount = RedisUtil.keyOps().incr(validCacheCountKey);
        // 缓存中获取可操作次数
        Object avlCountObj = RedisUtil.hashOps().hget(validKey, CommonConstant.VALID_COUNT_FIELD);
        Integer avlCount = Integer.parseInt(avlCountObj == null ? "0" : String.valueOf(avlCountObj));
        if (avlCount == 0) {
            avlCount = CommonConstant.DEFAULT_COUNT_FIELD;
        }
        LOGGER.info("短信验证码使用验证key：" + cacheKey + "验证错误次数：" + validCount + ",最大可输入的验证错误次数：" + avlCount);
        return validCount > avlCount;
    }

    /**
     * 判断redisKey对应的错误验证码验证次数是否在规定时间内超过规定值，如果超过验证次数，则返回true,否则返回false.
     * @param businessKey  业务服务key,如：CommonConstant.REDIS_PRE_DR
     * @param cacheKey
     */
    public static boolean validUserOperatorFlag(String businessKey, String cacheKey) {
        // 根据业务cacheKey，计算出验证validCacheKey和validCacheKey
        String validCacheTimeKey = cacheKey + "|time";
        String validKey = businessKey + "valid_exp";
        // 错误次数的记录已经过期，则直接返回false
        if (!RedisUtil.keyOps().existsKey(validCacheTimeKey)) {
            return false;
        }
        // 缓存中获取验证次数
        String validCacheCountKey = cacheKey + "|key";
        String validCountStr = RedisUtil.valueOps().getString(validCacheCountKey);
        long validCount = 0;
        if (StringUtils.isNotEmpty(validCountStr)) {
            validCount = Long.parseLong(validCountStr);
        }
        // 缓存中获取可操作次数
        Object avlCountObj = RedisUtil.hashOps().hget(validKey, CommonConstant.VALID_COUNT_FIELD);
        Integer avlCount = Integer.parseInt(avlCountObj == null ? "0" : String.valueOf(avlCountObj));
        if (avlCount == 0) {
            avlCount = CommonConstant.DEFAULT_COUNT_FIELD;
        }
        LOGGER.info("短信验证码发送查询验证key：" + cacheKey + "验证错误次数：" + validCount + ",最大可输入的验证错误次数：" + avlCount);
        return validCount > avlCount;
    }
}
